package org.apache.ocean.solr.search;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;

import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.Weight;
import org.apache.lucene.util.PriorityQueue;
import org.apache.ocean.main.search.Filters;
import org.apache.ocean.solr.util.Timeout;

public abstract class Search<V> implements Callable<Search.Result<V>> {
  protected final SearchQuery searchQuery;

  public Search(SearchQuery searchQuery) {
    this.searchQuery = searchQuery;
  }

  public static ScoreDoc[] toArray(PriorityQueue priorityQueue) {
    ScoreDoc[] scoreDocs = new ScoreDoc[priorityQueue.size()];
    for (int i = priorityQueue.size() - 1; i >= 0; i--)
      scoreDocs[i] = (ScoreDoc) priorityQueue.pop();
    return scoreDocs;
  }

  public abstract Search.Result<V> call() throws Exception;

  public static class Result<V> {
    private int start;
    private V[] allDocs;
    private int numFound;
    private long elapsed;

    public Result(int start, V[] allDocs, int numFound, long elapsed) {
      this.start = start;
      this.allDocs = allDocs;
      this.numFound = numFound;
      this.elapsed = elapsed;
    }

    public long getElapsed() {
      return elapsed;
    }

    public List<V> getDocs() {
      List<V> scoreDocs = new ArrayList<V>();
      if (start >= allDocs.length) {
        return scoreDocs;
      } else {
        for (int x = start; x < allDocs.length; x++) {
          scoreDocs.add(allDocs[x]);
        }
      }
      return scoreDocs;
    }

    public int getNumFound() {
      return numFound;
    }

    public V[] getAllDocs() {
      return allDocs;
    }
  }

  public static class SearchQuery {
    private Weight weight;
    private int start;
    private int rows;
    private Filters filters;
    private Sort sort;
    private Timeout timeout;

    public SearchQuery(Weight weight, int start, int rows, Filters filters,
        Sort sort, Timeout timeout) {
      this.weight = weight;
      this.start = start;
      this.rows = rows;
      this.filters = filters;
      this.sort = sort;
      this.timeout = timeout;
    }

    public boolean hasSort() {
      if (sort != null || sort.getSort().length > 0)
        return true;
      return false;
    }

    public int getNumDocs() {
      return start + rows;
    }

    public Timeout getTimeout() {
      return timeout;
    }

    public Weight getWeight() {
      return weight;
    }

    public int getStart() {
      return start;
    }

    public int getRows() {
      return rows;
    }

    public Filters getFilters() {
      return filters;
    }

    public Sort getSort() {
      return sort;
    }
  }
}
